// 类型定义
interface MimeTypeMap {
  [key: string]: string;
}

// 配置常量
const CONFIG = {
  READ_TIMEOUT: 5000, // 5秒
  UNKNOWN_TYPE: 'unknown' as const,
} as const;

// 文件签名映射表
const FILE_SIGNATURES: MimeTypeMap = {
  // 图片格式
  '89504E47': 'image/png', // 12 bytes
  FFD8FF: 'image/jpeg', // 12 bytes
  '47494638': 'image/gif', // 4 bytes
  '424D': 'image/bmp', // 4 bytes
  '49492A00': 'image/tiff', // 6 bytes
  '4949': 'image/tiff', // 4 bytes
  '4D4D': 'image/tiff', // 4 bytes

  // 视频格式
  '66747970': 'video/mp4', // 12 bytes
  '00000020': 'video/mp4', // 12 bytes
  '0000001C': 'video/mp4', // 12 bytes
  '3026B275': 'video/wmv', // 12 bytes
  '000001BA': 'video/mpeg', // 12 bytes
  '000001B3': 'video/mpeg', // 12 bytes
  '2321414D52': 'video/3gp', // 12 bytes
  '6D6F6F76': 'video/quicktime', // 12 bytes

  // 音频格式
  '49443303': 'audio/mp3', // 12 bytes
  '49443304': 'audio/mp3', // 12 bytes
  FFF3: 'audio/mp3', // 6 bytes
  FFF2: 'audio/mp3', // 6 bytes
  '57415645': 'audio/wav', // 12 bytes
  '4F676753': 'audio/ogg', // 12 bytes

  // 压缩文件格式
  '504B0304': 'application/zip', // 12 bytes
  '1F8B08': 'application/gzip', // 6 bytes

  // 文档格式
  '25504446': 'application/pdf', // 12 bytes
  D0CF11E0: 'application/msword', // 6 bytes
  '7B5C727466': 'application/rtf', // 12 bytes

  // 较长签名
  '5249464641564920': 'video/avi', // 12 bytes
  '524946464D546864': 'video/f4v', // 12 bytes
  '524946465745424D': 'video/webm', // 12 bytes
  '5249464657415645': 'audio/wav', // 12 bytes
  '664C614300000022': 'audio/flac', // 14 bytes
};

// 文件类型缓存
const fileTypeCache = new WeakMap<File, string>();
// 计算最大签名长度
const maxLength = Math.max(...Object.keys(FILE_SIGNATURES).map((sig) => sig.length));

/**
 * 根据文件头部解析 MIME 类型
 */
const getMimeTypeByHeader = (header: string): string => {
  // 检查所有可能的签名长度
  for (let length = 2; length <= header.length; length += 2) {
    const signature = header.slice(0, length);
    const mimeType = FILE_SIGNATURES[signature];
    if (mimeType) {
      return mimeType;
    }
  }

  // 如果没有找到合适的 MIME 类型，返回 "unknown"
  return CONFIG.UNKNOWN_TYPE;
};

/**
 * 通过文件签名检测文件类型
 */
export const getFileTypeByMagicNumber = async (file: File): Promise<string> => {
  // 先查缓存
  if (fileTypeCache.has(file)) {
    return fileTypeCache.get(file)!;
  }

  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    const timeout = setTimeout(() => {
      reader.abort();
      reject(new Error('File reading timeout'));
    }, CONFIG.READ_TIMEOUT);

    reader.onloadend = (e: ProgressEvent<FileReader>): void => {
      clearTimeout(timeout);

      if (!e.target?.result) {
        fileTypeCache.set(file, CONFIG.UNKNOWN_TYPE);
        resolve(CONFIG.UNKNOWN_TYPE);
        return;
      }

      const arr = new Uint8Array(e.target.result as ArrayBuffer);
      const header = Array.from(arr)
        .map((byte) => byte.toString(16).padStart(2, '0'))
        .join('')
        .toUpperCase();

      const mimeType = getMimeTypeByHeader(header);
      fileTypeCache.set(file, mimeType);
      resolve(mimeType);
    };

    reader.onerror = (e): void => {
      clearTimeout(timeout);
      if (e.target && e.target.error) {
        reject(new Error(e.target.error.message || 'Failed to read file'));
      } else {
        reject(new Error('Failed to read file'));
      }
    };

    try {
      reader.readAsArrayBuffer(file.slice(0, maxLength / 2));
    } catch (error) {
      clearTimeout(timeout);
      reject(error);
    }
  });
};
